package org.finesys.common.netty.websocket.resolver;

import static org.finesys.common.netty.websocket.constants.WebSocketAttributeKeyConstants.REQUEST_PARAM;

import java.util.List;
import java.util.Map;

import org.finesys.common.netty.websocket.annotation.RequestParam;
import org.finesys.common.netty.websocket.support.MethodArgumentResolver;
import org.springframework.beans.TypeConverter;
import org.springframework.beans.factory.support.AbstractBeanFactory;
import org.springframework.core.MethodParameter;

import io.netty.channel.Channel;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.QueryStringDecoder;

public class RequestParamMethodArgumentResolver implements MethodArgumentResolver {

    private final AbstractBeanFactory beanFactory;

    /**
     * 构造函数，用于创建RequestParamMethodArgumentResolver实例。
     *
     * @param beanFactory Spring的AbstractBeanFactory接口的实现，用于解析和创建Bean。
     */
    public RequestParamMethodArgumentResolver(AbstractBeanFactory beanFactory) {
        this.beanFactory = beanFactory;
    }

    /**
     * 重写support方法以判断是否支持给定的方法参数。
     * <p>
     * 如果方法参数上标注了@RequestParam注解，则返回true，表示支持该参数；
     * 否则返回false。
     *
     * @param parameter 方法参数，包含方法参数的元数据。
     * @return 如果支持给定的方法参数，则返回true；否则返回false。
     */
    @Override
    public boolean support(MethodParameter parameter) {
        return parameter.hasParameterAnnotation(RequestParam.class);
    }

    /**
     * 重写resolveArgument方法以解析方法参数。
     * <p>
     * 此方法用于从WebSocket通道接收到的请求中解析出方法参数。它首先检查方法参数上是否标注了@RequestParam注解，
     * 然后从请求参数中获取对应的值。如果参数名未在@RequestParam注解中指定，则尝试从方法参数名中获取。
     * 如果请求参数中不存在该参数名，将抛出IllegalArgumentException异常。
     * <p>
     * 如果通道尚未存储请求参数，则使用QueryStringDecoder解析请求URI中的查询参数，并将其存储在通道属性中。
     * <p>
     * 根据方法参数的类型，将请求参数转换为相应的类型。如果方法参数类型为List，则直接将请求参数列表转换并返回；
     * 否则，将请求参数列表中的第一个元素转换并返回。如果请求参数不存在，但@RequestParam注解中指定了默认值，
     * 则将默认值转换为相应类型并返回；如果默认值也不存在，则返回null。
     *
     * @param parameter 方法参数，包含方法参数的元数据。
     * @param channel   WebSocket通道，用于处理WebSocket连接。
     * @param object    从WebSocket通道接收到的对象，预期为FullHttpRequest类型。
     * @return 解析并转换后的方法参数值。
     * @throws Exception 如果在解析或转换参数过程中发生异常，则抛出该异常。
     */
    @Override
    public Object resolveArgument(MethodParameter parameter, Channel channel, Object object) throws Exception {
        RequestParam requestParam = parameter.getParameterAnnotation(RequestParam.class);
        if(requestParam==null){
            throw new IllegalAccessException("requestParam 不能为空");
        }
        String name = requestParam.value();
        if (name.isEmpty()) {
            name = parameter.getParameterName();
            if (name == null) {
                throw new IllegalArgumentException(
                        "Name for argument type [" + parameter.getNestedParameterType().getName()
                                + "] not available, and parameter name information not found in class file either.");
            }
        }

        if (!channel.hasAttr(REQUEST_PARAM)) {
            QueryStringDecoder decoder = new QueryStringDecoder(((FullHttpRequest) object).uri());
            channel.attr(REQUEST_PARAM).set(decoder.parameters());
        }
        Map<String, List<String>> requestParams = channel.attr(REQUEST_PARAM).get();
        List<String> args = (requestParams != null ? requestParams.get(name) : null);
        TypeConverter typeConverter = beanFactory.getTypeConverter();
        if (args == null) {
            if ("\n\t\t\n\t\t\n\uE000\uE001\uE002\n\t\t\t\t\n".equals(requestParam.defaultValue())) {
                return null;
            } else {
                return typeConverter.convertIfNecessary(requestParam.defaultValue(), parameter.getParameterType());
            }
        }

        if (List.class.isAssignableFrom(parameter.getParameterType())) {
            return typeConverter.convertIfNecessary(args, parameter.getParameterType());
        } else {
            return typeConverter.convertIfNecessary(args.get(0), parameter.getParameterType());
        }
    }
}
